#ifndef __RING_BUFFER_H__
#define __RING_BUFFER_H__

#include <stdbool.h>
#include <stdint.h>

/**
 * @brief 	 清空索引
 */
#define RB_INDEX_CLEAR(rb_index) \
    do {                         \
        (rb_index).flag  = 0;    \
        (rb_index).index = 0;    \
    } while (0)

/**
 * @brief 	 复制索引
 */
#define RB_INDEX_COPY(target_index, source_index)    \
    do {                                             \
        (source_index).flag  = (target_index).flag;  \
        (source_index).index = (target_index).index; \
    } while (0)

/**
 * @brief 	 索引尾部处理
 */
#define RB_INDEX_END(rb_index, rb_elem_max)      \
    do {                                         \
        if ((rb_index).index >= (rb_elem_max)) { \
            (rb_index).flag = !(rb_index).flag;  \
            (rb_index).index %= (rb_elem_max);   \
        }                                        \
    } while (0)

/**
 * @brief 	 错误类型
 */
typedef enum _RingBufferErrType
{
    RB_OK = 0,     ///< 没有问题
    RB_PARAMS_ERR, ///< 参数错误
    RB_OVERWRITE,  ///< 数据覆盖了
    RB_EMPTY,      ///< 缓存区空
} RingBufferErrType;

/**
 * @brief 	 索引
 */
typedef struct _RingBufferIndex
{
    uint32_t flag : 1;
    uint32_t index : 31;
} RingBufferIndex;

/**
 * @brief 	 环形缓存区配置
 */
typedef struct _RingBufferConfig
{
    uint8_t is_dma_store : 1;      ///< 是否使用dma存储数据
    uint8_t allow_overwrite : 1;   ///< 是否允许覆盖
    uint8_t allow_sqlit_store : 1; ///< 是否允许分割存放
} RingBufferConfig;

/**
 * @brief 	 环形缓存区
 */
typedef struct _RingBuffer
{
    void *elem_buffer;       ///< 缓冲区
    uint32_t elem_size;      ///< 每个缓冲元素大小
    uint32_t elem_max;       ///< 元素数量
    RingBufferIndex r;       ///< 读索引
    RingBufferIndex w;       ///< 写索引
    RingBufferConfig config; ///< 配置
    void (*lock)(void);      ///< 加锁操作
    void (*unlock)(void);    ///< 解锁操作
} RingBuffer;

/**
 * @fn RB_init
 * @brief 初始化环形缓冲区
 * @param rb [in] 环形缓冲区对象指针
 * @param elem_buffer [in] 环形缓冲区的元素缓存数组
 * @param elem_size [in] 每个元素的大小（单位: Byte）
 * @param elem_max [in] 元素缓存数组最多缓存的元素数量
 * @param lock [in] 加锁操作，用于数据存取的互斥操作
 * @param unlock [in] 解锁操作，用于数据存取的互斥操作
 * @return RingBufferErrType 错误类型
 */
extern RingBufferErrType RB_init(RingBuffer *rb, void *elem_buffer, uint32_t elem_size, uint32_t elem_max, void (*lock)(void), void (*unlock)(void));

/**
 * @fn RB_config
 * @brief 配置环形缓冲区
 * @param rb [in] 环形缓冲区对象指针
 * @param config [in] 环形缓冲区的配置结构体
 * @return RingBufferErrType 错误类型
 */
extern RingBufferErrType RB_config(RingBuffer *rb, RingBufferConfig *config);

/**
 * @fn RB_push
 * @brief 往环形缓冲区中存放元素（数据）
 * @param rb [in] 环形缓冲区对象指针
 * @param elem [in] 需要存放的元素指针或者需要存放的元素数组
 * @param num [in] 需要存放的元素数量
 * @param start [out] 元素在缓冲区存放的位置索引头，用于给外部提供该数据的存放信息，不需要时传入NULL（0）
 * @param end [out] 元素在缓冲区存放的位置索引尾，用于给外部提供该数据的存放信息，不需要时传入NULL（0）
 * @return RingBufferErrType 错误类型
 */
extern RingBufferErrType RB_push(RingBuffer *rb, const void *elem, const uint32_t num, uint32_t *start, uint32_t *end);

/**
 * @fn RB_push_dma
 * @brief 使用DMA往环形缓冲区中存放元素（数据）
 * @param rb [in] 环形缓冲区对象指针
 * @param pos [in] DMA存入数据后，数据尾索引
 * @param start [out] 元素在缓冲区存放的位置索引头，用于给外部提供该数据的存放信息，不需要时传入NULL（0）
 * @param end [out] 元素在缓冲区存放的位置索引尾，用于给外部提供该数据的存放信息，不需要时传入NULL（0）
 * @return RingBufferErrType 错误类型
 */
extern RingBufferErrType RB_push_dma(RingBuffer *rb, const uint32_t pos, uint32_t *start, uint32_t *end);

/**
 * @fn RB_pop
 * @brief 从环形缓冲区取出num数量的元素，取出后释放了相应的元素
 * @param rb [in] 环形缓冲区对象指针
 * @param num [in] 需要取出的元素数量
 * @param elem [out] 取出元素存放缓冲区，必须提供有效的指针
 * @return RingBufferErrType 错误类型
 */
extern RingBufferErrType RB_pop(RingBuffer *rb, const uint32_t num, void *elem);

/**
 * @fn RB_look
 * @brief 查看环形缓冲区的num个元素，不会释放元素，仅仅查看
 * @param rb [in] 环形缓冲区对象指针
 * @param num [in] 需要查看的元素数量
 * @param elem [out] 查看元素存放缓冲区，必须提供有效的指针
 * @return RingBufferErrType 错误类型
 */
extern RingBufferErrType RB_look(RingBuffer *rb, const uint32_t num, void *elem);

#endif
